package com.gpc.hexapods.layer;

import android.graphics.PointF;
import android.opengl.GLES20;

import com.gpc.hexapods.data.Leg1Data;
import com.gpc.hexapods.data.Leg2Data;
import com.gpc.hexapods.data.Leg3Data;
import com.gpc.hexapods.data.Point;
import com.gpc.hexapods.utils.MathUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

public class LegLayer {

    private static final String TAG = "LegLayer";

    private static final int POINT_LENGTH = 24;
    private static final int INDEX_LENGTH = 36;
    private static final int COLOR_LENGTH = 36;

    private Point mBasePoint;
    private Leg1Data mLeg1Data;
    private Leg2Data mLeg2Data;
    private Leg3Data mLeg3Data;

    private int mPositionHandle;
    private int mColorHandle;

    private FloatBuffer mPosition1Buffer;
    private ShortBuffer mIndex1Buffer;
    private FloatBuffer mColor1Buffer;

    private FloatBuffer mPosition2Buffer;
    private ShortBuffer mIndex2Buffer;
    private FloatBuffer mColor2Buffer;

    private FloatBuffer mPosition3Buffer;
    private ShortBuffer mIndex3Buffer;
    private FloatBuffer mColor3Buffer;

    public LegLayer(Point point1, float aAngle, float bAngle, float cAngle) {
        Point point2 = getPoint2(point1, aAngle);
        Point point3 = getPoint3(point2, aAngle, bAngle);
        Point point4 = getPoint4(point3, aAngle, bAngle, cAngle);

        mBasePoint = point1;
        mLeg1Data = new Leg1Data(point1, aAngle);
        mLeg2Data = new Leg2Data(point2, point3, aAngle, bAngle);
        mLeg3Data = new Leg3Data(point3, point4, aAngle, bAngle, cAngle);

        mPosition1Buffer = ByteBuffer.allocateDirect(mLeg1Data.position.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mPosition1Buffer.put(mLeg1Data.position);
        mPosition1Buffer.position(0);

        mIndex1Buffer = ByteBuffer.allocateDirect(mLeg1Data.index.length * 2)
                .order(ByteOrder.nativeOrder())
                .asShortBuffer();
        mIndex1Buffer.put(mLeg1Data.index);
        mIndex1Buffer.position(0);

        mColor1Buffer = ByteBuffer.allocateDirect(mLeg1Data.color.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mColor1Buffer.put(mLeg1Data.color);
        mColor1Buffer.position(0);

        mPosition2Buffer = ByteBuffer.allocateDirect(mLeg2Data.position.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mPosition2Buffer.put(mLeg2Data.position);
        mPosition2Buffer.position(0);

        mIndex2Buffer = ByteBuffer.allocateDirect(mLeg2Data.index.length * 2)
                .order(ByteOrder.nativeOrder())
                .asShortBuffer();
        mIndex2Buffer.put(mLeg2Data.index);
        mIndex2Buffer.position(0);

        mColor2Buffer = ByteBuffer.allocateDirect(mLeg2Data.color.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mColor2Buffer.put(mLeg2Data.color);
        mColor2Buffer.position(0);

        mPosition3Buffer = ByteBuffer.allocateDirect(mLeg3Data.position.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mPosition3Buffer.put(mLeg3Data.position);
        mPosition3Buffer.position(0);

        mIndex3Buffer = ByteBuffer.allocateDirect(mLeg3Data.index.length * 2)
                .order(ByteOrder.nativeOrder())
                .asShortBuffer();
        mIndex3Buffer.put(mLeg3Data.index);
        mIndex3Buffer.position(0);

        mColor3Buffer = ByteBuffer.allocateDirect(mLeg3Data.color.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mColor3Buffer.put(mLeg3Data.color);
        mColor3Buffer.position(0);
    }
    public void setAngle(float[] angle) {
        setAngle(angle[0], angle[1], angle[2]);
    }

    public void setAngle(float aAngle, float bAngle, float cAngle) {
        Point point2 = getPoint2(mBasePoint, aAngle);
        Point point3 = getPoint3(point2, aAngle, bAngle);
        Point point4 = getPoint4(point3, aAngle, bAngle, cAngle);

        float[] position1Array = mLeg1Data.getPosition(mBasePoint, aAngle);
        mPosition1Buffer.clear();
        mPosition1Buffer.put(position1Array);
        mPosition1Buffer.position(0);

        float[] position2Array = mLeg2Data.getPosition(point2, point3, aAngle, bAngle);
        mPosition2Buffer.clear();
        mPosition2Buffer.put(position2Array);
        mPosition2Buffer.position(0);

        float[] position3Array = mLeg3Data.getPosition(point3, point4, aAngle, bAngle, cAngle);
        mPosition3Buffer.clear();
        mPosition3Buffer.put(position3Array);
        mPosition3Buffer.position(0);
    }

    private Point getPoint2(Point point, float aAngle) {
        float x = point.x + 0.29f * MathUtil.cos(aAngle);
        float y = point.y + 0.29f * MathUtil.sin(aAngle);
        return new Point(x, y);
    }

    private Point getPoint3(Point point, float aAngle, float bAngle) {
        float x = point.x + Leg2Data.LENGTH * MathUtil.cos(bAngle) * MathUtil.cos(aAngle);
        float y = point.y + Leg2Data.LENGTH * MathUtil.cos(bAngle) * MathUtil.sin(aAngle);
        float z = point.z + Leg2Data.LENGTH * MathUtil.sin(bAngle);
        return new Point(x, y, z);
    }

    private Point getPoint4(Point point, float aAngle, float bAngle, float cAngle) {
        float angle = cAngle - (90 - bAngle);
        float x = point.x + Leg3Data.LENGTH * MathUtil.sin(angle) * MathUtil.cos(aAngle);
        float y = point.y + Leg3Data.LENGTH * MathUtil.sin(angle) * MathUtil.sin(aAngle);
        float z = point.z - Leg3Data.LENGTH * MathUtil.cos(angle);
        return new Point(x, y, z);
    }

    public void setHandle(int positionHandle, int colorHandle) {
        mPositionHandle = positionHandle;
        mColorHandle = colorHandle;
    }

    public void onDraw() {
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mPosition1Buffer);
        GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mColor1Buffer);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, mLeg1Data.index.length, GLES20.GL_UNSIGNED_SHORT, mIndex1Buffer);

        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mPosition2Buffer);
        GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mColor2Buffer);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, mLeg2Data.index.length, GLES20.GL_UNSIGNED_SHORT, mIndex2Buffer);

        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mPosition3Buffer);
        GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mColor3Buffer);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, mLeg3Data.index.length, GLES20.GL_UNSIGNED_SHORT, mIndex3Buffer);
    }
}
